import type { MenuItemRow } from "@/components/AppLayout/components/AppMenu.vue";
import type { VNode } from "vue";
import { ref, computed, watch, provide, inject } from "vue";
import { useRoute } from "vue-router";
import { useAsyncState } from "@vueuse/core";
import { useService } from "@/composables/useService";
import { useUserSession } from "@/composables/useUserSession";
import { getBaseUrl } from "@/utils/getBaseUrl";
import { groupBy } from "zf-utilz";

export function useApplicationStateProvide() {
  const service = useService();
  const route = useRoute();

  // 用户信息
  const {
    isLoading: userSessionisLoading,
    userInfo,
    isApplicationLogin
  } = useUserSession();

  // 应用ID
  const applicationId = computed(() => userInfo.value?.appId);
  const applicationBasePath = computed(() => "/");

  // 应用信息
  const {
    state: applicationInfo,
    isLoading: applicationInfoLoading,
    execute: updateApplicationInfo
  } = useAsyncState(
    async function () {
      if (!isApplicationLogin.value) return null;
      if (!applicationId.value) return null;
      return service.application.getApplication({
        applicationId: applicationId.value
      });
    },
    null,
    { immediate: false, resetOnExecute: false }
  );

  // 应用资源
  const {
    state: applicationResource,
    isLoading: applicationResourceLoading,
    execute: updateApplicationResource
  } = useAsyncState(
    async function () {
      if (!isApplicationLogin.value) return [];
      if (!applicationId.value) return [];
      return service.system.getCurrentUserAppResource();
    },
    [],
    { immediate: false, resetOnExecute: false }
  );

  // 应用菜单
  const applicationMenu = computed(() => {
    if (!applicationInfo.value) return [];
    if (!applicationResource.value?.length) return [];
    const groupedMenu = groupBy(
      applicationResource.value ?? [],
      item => item.label
    );

    const menu = [] as MenuItemRow[];
    for (const key in groupedMenu) {
      menu.push({
        label: key,
        path: getBaseUrl(
          groupedMenu[key].map(item =>
            pathJoin(applicationBasePath.value, item.href)
          )
        ),
        iconClass: groupedMenu[key][0].icon,
        children: groupedMenu[key].map(item => {
          return {
            label: item.page,
            path: pathJoin(applicationBasePath.value, item.href)
          };
        })
      });
    }
    return menu;
  });

  // -----------------------------------------------------------------------

  // 应用资源排序
  const applicationResourceSort = computed(() => {
    return [...applicationResource.value].sort((a, b) => {
      const aArr = a.href.replace(/\/$/, "").split("/");
      const bArr = b.href.replace(/\/$/, "").split("/");
      return bArr.length - aArr.length;
    });
  });

  // 当前路由权限
  const routeResourceKeys = computed(() => {
    const permission = applicationResourceSort.value.find(item => {
      const path = pathJoin(applicationBasePath.value, item.href);
      return path === route.path || whetherPathParent(route.path, path);
    });
    return permission?.buttonList?.map(item => item.label) ?? [];
  });

  // 检查是否有按钮权限
  const checkApplicationPermission = (key: string | string[]) => {
    const keys = Array.isArray(key) ? key : [key];
    return keys.some(item => routeResourceKeys.value.includes(item));
  };

  // vue 指令 检查应用权限
  const map = new WeakMap();
  const vApplicationPermission = ref({
    mounted(
      el: HTMLElement,
      binding: { value: string | string[] },
      _vnode: VNode
    ) {
      if (binding.value && !checkApplicationPermission(binding.value)) {
        if (el.parentNode) {
          map.set(el, el.parentNode);
          el.parentNode.removeChild(el);
        }
      }
    },
    updated(
      el: HTMLElement,
      binding: { value: string | string[] },
      _vnode: VNode
    ) {
      if (binding.value && !checkApplicationPermission(binding.value)) {
        if (el.parentNode) {
          map.set(el, el.parentNode);
          el.parentNode.removeChild(el);
        }
      } else {
        if (map.has(el)) {
          map.get(el)?.appendChild(el);
          map.delete(el);
        }
      }
    },
    beforeUnmount(el: HTMLElement) {
      el.parentNode?.removeChild(el);
      map.delete(el);
    }
  });

  // -----------------------------------------------------------------------

  // 学校信息
  const {
    state: schoolInfo,
    isLoading: schoolInfoLoading,
    execute: updateSchoolInfo
  } = useAsyncState(
    async function () {
      if (userInfo.value?.tenantType !== "school") return null;
      return service.baseData.getCurrentUserSchoolInfo();
    },
    null,
    { immediate: false, resetOnExecute: false }
  );

  // -----------------------------------------------------------------------

  // 应用加载
  const loading = computed(() => {
    if (userSessionisLoading.value) return true;
    if (applicationInfoLoading.value) return true;
    if (applicationResourceLoading.value) return true;
    if (schoolInfoLoading.value) return true;
    return false;
  });

  const isInit = ref(false);
  watch(
    () => loading.value,
    (value, olbValue) => {
      if (
        !userSessionisLoading.value &&
        !isInit.value &&
        olbValue === true &&
        value === false
      ) {
        isInit.value = true;
      }
    }
  );

  // v-application-permission="['编辑']"

  watch(
    () => applicationId.value,
    async () => {
      updateApplicationInfo();
      updateApplicationResource();
    },
    { immediate: true }
  );
  watch(
    () => userInfo.value?.tenantType,
    async () => {
      updateSchoolInfo();
    },
    { immediate: true }
  );

  const applicationState = {
    loading,
    isInit,
    applicationInfo,
    applicationMenu,
    schoolInfo,

    vApplicationPermission,

    checkApplicationPermission
  };

  provide("application-state", applicationState);
  return applicationState;
}

export function useApplicationState() {
  const applicationState =
    inject<ReturnType<typeof useApplicationStateProvide>>("application-state")!;
  if (!applicationState)
    throw new Error(
      "未找到 application-state，请检查是否已调用 useApplicationStateProvide"
    );
  return applicationState;
}

// 判断路径是否在该路径下
function whetherPathParent(path: string, parent: string) {
  if (!path) return false;
  if (!parent) return false;
  const parentArray = parent.replace(/\/$/, "").split("/");
  const pathArray = path.replace(/\/$/, "").split("/");

  return !parentArray.some((parentItem, index) => {
    return parentItem !== pathArray[index];
  });
}

// 路径拼接
function pathJoin(...args: string[]) {
  return args.reduce((pre, cur) => {
    return pre.replace(/\/$/, "") + "/" + cur.replace(/^\//, "");
  });
}
